package com.kefu.exam.service;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.kefu.common.context.KefuContext;
import com.kefu.common.exception.BusinessException;
import com.kefu.common.util.JacksonUtil;
import com.kefu.exam.enums.TipType;
import com.kefu.exam.mapper.*;
import com.kefu.exam.model.*;
import com.kefu.exam.vo.*;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.postgresql.ssl.LazyKeyManager;
import org.springframework.stereotype.Service;
import com.kefu.common.service.AbstractKefuService;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author xy
 * @date 2022/02/28
 */
@Slf4j
@Service
public class ExamSubjectService extends AbstractKefuService<ExamSubject> {
    @Resource
    protected ExamSubjectMapper examSubjectMapper;
    @Resource
    protected ExamPaperSubjectMapper examPaperSubjectMapper;
    @Resource
    protected ExamSubjectTypeMapper examSubjectTypeMapper;
    @Resource
    protected ExamSubjectAnswerMapper examSubjectAnswerMapper;
    @Resource
    protected ExamCascadeJumpMapper examCascadeJumpMapper;


    public SubjectUnit addSubject(ExamSubjectInsertVo vo) {
        SubjectUnit unit = null;
        KefuContext context = KefuContext.getKefuContext();
        // 1.填空，2.单选，3.多选，4判断，5问答 7 综合
        if ("1".equals(vo.getTypeId())) {
            unit = TipType.Vacancy.getHandle().expressTextSubject(vo, vo.getTypeId(),
                    context, this, examSubjectAnswerMapper, examSubjectMapper);
        }
        if ("2".equals(vo.getTypeId())) {
            unit = TipType.Select.getHandle().expressTextSubject(vo, vo.getTypeId(),
                    context, this, examSubjectAnswerMapper, examSubjectMapper);
        }
        if ("3".equals(vo.getTypeId())) {
            unit = TipType.CheckBox.getHandle().expressTextSubject(vo, vo.getTypeId(),
                    context, this, examSubjectAnswerMapper, examSubjectMapper);
        }
        if ("4".equals(vo.getTypeId())) {
            unit = TipType.Judge.getHandle().expressTextSubject(vo, vo.getTypeId(),
                    context, this, examSubjectAnswerMapper, examSubjectMapper);
        }
        if ("5".equals(vo.getTypeId())) {
            unit = TipType.Interlocution.getHandle().expressTextSubject(vo, vo.getTypeId(),
                    context, this, examSubjectAnswerMapper, examSubjectMapper);
        }
        if ("7".equals(vo.getTypeId())) {
            unit = TipType.Comprehensive.getHandle().expressTextSubject(vo, vo.getTypeId(),
                    context, this, examSubjectAnswerMapper, examSubjectMapper);
        }
        if (unit == null) {
            throw BusinessException.msg("无法解析的题类型");
        }
        return unit;
    }


    public SubjectUnit initSubjectUnit(ExamSubject subject, TipType vacancy, String subjectTypeId, KefuContext context) {
        SubjectUnit unit = new SubjectUnit();
        // 创建一个试题临时对象-----------------------------------
        int i = examSubjectMapper.insert(subject);
        logger.info("创建试题[{}] :{}", i, JacksonUtil.toString(subject));
        // -----------------------------
        ExamSubjectType subjectType = examSubjectTypeMapper.selectByPrimaryKey(subjectTypeId);
        logger.info("获取到试题的分类信息:{}", JacksonUtil.toString(subjectType));
        unit.setSubject(subject);
        unit.setSubjectType(subjectType);
        unit.setTipType(vacancy);
        logger.info("创建试题: {}", JacksonUtil.toString(unit));
        return unit;
    }


    public SubjectUnit getSubjectUnit(String subjectId) {
        SubjectUnit unit = new SubjectUnit();
        ExamSubject subject = baseMapper.selectByPrimaryKey(subjectId);
        if (Objects.isNull(subject)) {
            return unit;
        }
        unit.setSubject(subject);
        unit.setSubjectType(examSubjectTypeMapper.selectByPrimaryKey(unit.getSubject().getTypeId()));
        unit.setTipType(TipType.getTipType(unit.getSubject().getTypeId()));
        List<AnswerUnit> answerUnitList = new ArrayList<>();
        List<ExamSubjectAnswer> answers = examSubjectAnswerMapper.selectList(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                .eq(ExamSubjectAnswer::getSubjectId, subjectId).orderByAsc(ExamSubjectAnswer::getAnswerSort));
        for (ExamSubjectAnswer answer : answers) {
            List<SubjectUnit> subjectUnitList = new ArrayList<>();
            AnswerUnit answerunit = new AnswerUnit();
            answerunit.setAnswer(answer);
            List<ExamSubject> examSubjectList = examSubjectMapper.selectList(Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getFatherSubject, answer.getAnswerId())
                    .eq(ExamSubject::getTenantId, KefuContext.getKefuContext().getTenantId())
                    .eq(ExamSubject::getSubjectStatus, 1)
                    .in(ExamSubject::getTypeId, "2", "3", "5", "7"));
            if (examSubjectList != null && examSubjectList.size() > 0) {
                for (ExamSubject examSubject : examSubjectList) {
                    SubjectUnit subjectUnit = getSubjectUnit(examSubject.getSubjectId());
                    subjectUnitList.add(subjectUnit);
                }
            }
            answerunit.setSonSubjectList(subjectUnitList);
            answerUnitList.add(answerunit);
        }
        unit.setAnswers(answerUnitList);
        return unit;
    }

    public ExamSubjectUnitVo processData(SubjectUnit unit) {
        ExamSubjectUnitVo vo = new ExamSubjectUnitVo();
        vo.setSubject(unit.getSubject());
        vo.setTipType(unit.getTipType());
        vo.setSubjectType(unit.getSubjectType());
        List<AnswerUnitVo> answerUnitListVo = new ArrayList<>();
        for (AnswerUnit answerUnit : unit.getAnswers()) {
            List<ExamSonSubjectVo> examSonSubjectVoList = new ArrayList<>();
            AnswerUnitVo answerUnitVo = new AnswerUnitVo();
            answerUnitVo.setAnswer(answerUnit.getAnswer());
            answerUnitVo.setJump(answerUnit.getJump());
            for (SubjectUnit subjectUnit : answerUnit.getSonSubjectList()) {
                ExamSonSubjectVo examSonSubjectVo = new ExamSonSubjectVo();
                examSonSubjectVo.setSubjectId(subjectUnit.getSubject().getSubjectId());
                examSonSubjectVo.setSubjectContent(subjectUnit.getSubject().getSubjectContent());
                examSonSubjectVoList.add(examSonSubjectVo);
            }
            answerUnitVo.setExamSonSubjectVo(examSonSubjectVoList);
            answerUnitListVo.add(answerUnitVo);
        }
        vo.setAnswers(answerUnitListVo);
        return vo;
    }


    public String deleteSubject(String id) {
        // 1. 判断是否存在
        ExamSubject info = examSubjectMapper.selectByPrimaryKey(id);
        if (Objects.isNull(info)) {
            throw BusinessException.msg("问题已经被删除");
        }
        // 2. 是否已经被问卷关联
        List<ExamPaperSubject> list = examPaperSubjectMapper.selectList(Wrappers.lambdaQuery(ExamPaperSubject.class)
                .eq(ExamPaperSubject::getSubjectId, id));
        if (null != list && list.size() > 0) {
            throw BusinessException.msg("问卷已经关联了这个问题");
        }
        List<ExamSubjectAnswer> answerList = examSubjectAnswerMapper.selectList(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                .eq(ExamSubjectAnswer::getSubjectId, id));
        if (answerList != null && answerList.size() > 0) {
            LambdaQueryWrapper<ExamSubject> wrapper = new LambdaQueryWrapper<>();
            for (ExamSubjectAnswer answer : answerList) {
                wrapper.eq(ExamSubject::getFatherSubject, answer.getAnswerId())
                        .or();
            }
            List<ExamSubject> examSubjectList = examSubjectMapper.selectList(wrapper);
            if (examSubjectList != null && examSubjectList.size() > 0) {
                throw BusinessException.msg("此问题已关联子问题");
            }
        }
        if (info.getFatherSubject() != null && info.getFatherSubject().equals("")) {
            throw BusinessException.msg("此问题已关联父问题");
        }
        int i = examSubjectMapper.delete(Wrappers.lambdaQuery(ExamSubject.class)
                .eq(ExamSubject::getSubjectId, id));
        examSubjectAnswerMapper.delete(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                .eq(ExamSubjectAnswer::getSubjectId, id));
        logger.info("删除试题[{}]:{}", i, JacksonUtil.toString(info));
        // 3. 同步删除版本信息
        return info.getSubjectId();
    }


    public String deleteExamSubject(String subjectId, String paperId) {
        if (!StringUtils.isNotBlank(subjectId)) {
            throw BusinessException.msg("未选择要删除的问题");
        }
        String[] id = subjectId.split(",");
        LambdaQueryWrapper<ExamPaperSubject> wrapper = Wrappers.lambdaQuery(ExamPaperSubject.class);
        wrapper.eq(StringUtils.isNotBlank(paperId), ExamPaperSubject::getPaperId, paperId)
                .in(ExamPaperSubject::getSubjectId, id);
        //查询所要删除的数据
        int delete = examPaperSubjectMapper.delete(wrapper);
        if (delete <= 0) {
            throw BusinessException.msg("删除失败");
        }
        List<ExamCascadeJump> examCascadeJumpList = examCascadeJumpMapper.selectList(Wrappers.lambdaQuery(ExamCascadeJump.class)
                .eq(ExamCascadeJump::getPaperId, paperId));
        if (examCascadeJumpList != null && examCascadeJumpList.size() > 0) {
            int remove = examCascadeJumpMapper.delete(Wrappers.lambdaQuery(ExamCascadeJump.class)
                    .eq(ExamCascadeJump::getPaperId, paperId));
            logger.info("问卷跳转规则，删除[{}]问卷中[{}]条规则", paperId, remove);
            if (remove <= 0) {
                throw BusinessException.msg("跳转规则删除失败");
            }
        }
        return "删除成功";
    }


    public String updateSubject(ExamSubjectInsertVo vo) {
        KefuContext context = KefuContext.getKefuContext();
        ExamSubject examSubject = vo.convert();
        examSubject.setSubjectId(vo.getSubjectId());
        // 1.填空，2.单选，3.多选，4判断，5问答 7.综合
        if ("2".equals(vo.getTypeId())) {
            examSubjectMapper.update(examSubject, Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getSubjectId, examSubject.getSubjectId()));
            examSubjectAnswerMapper.delete(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                    .eq(ExamSubjectAnswer::getSubjectId, examSubject.getSubjectId()));
            addSubjectS(vo, context);
            return vo.getSubjectId();

        }
        if ("3".equals(vo.getTypeId())) {
            examSubjectMapper.update(examSubject, Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getSubjectId, examSubject.getSubjectId()));
            examSubjectAnswerMapper.delete(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                    .eq(ExamSubjectAnswer::getSubjectId, examSubject.getSubjectId()));
            addSubjectS(vo, context);
            return vo.getSubjectId();
        } else if ("5".equals(vo.getTypeId())) {
            examSubjectMapper.update(examSubject, Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getSubjectId, examSubject.getSubjectId()));
            examSubjectAnswerMapper.delete(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                    .eq(ExamSubjectAnswer::getSubjectId, examSubject.getSubjectId()));
            addSubjectS(vo, context);
            return vo.getSubjectId();
        } else if ("7".equals(vo.getTypeId())) {
            examSubjectMapper.update(examSubject, Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getSubjectId, examSubject.getSubjectId()));
            examSubjectAnswerMapper.delete(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                    .eq(ExamSubjectAnswer::getSubjectId, examSubject.getSubjectId()));
            addSubjectS(vo, context);
            return vo.getSubjectId();
        } else {
            throw BusinessException.msg("无法解析的题类型");
        }

    }

    private void addSubjectS(ExamSubjectInsertVo vo, KefuContext context) {
        if (null != vo.getExamSubjectAnswerList() && vo.getExamSubjectAnswerList().size() > 0) {
            List<ExamSubjectUpdateListVo> updateListVo = new ArrayList<>();
            List<ExamSubjectAnswer> examSubjectAnswerList = vo.getExamSubjectAnswerList();
            for (int i = 0; i < examSubjectAnswerList.size(); i++) {
                ExamSubjectAnswer answer = examSubjectAnswerList.get(i);
                answer.setCreateTime(context.getNow());
                answer.setCreateUser(context.getUserId());
                answer.setCreateName(context.getUserName());
                answer.setAnswerStatus(1);
                answer.setAnswerSort(i);
                answer.setAnswerId(IdUtil.simpleUUID());
                answer.setSubjectId(vo.getSubjectId());
                int x = examSubjectAnswerMapper.insert(answer);
                ExamSubjectUpdateListVo updateVo = new ExamSubjectUpdateListVo();
                updateVo.setAnswerId(answer.getAnswerId());
                updateVo.setSubjectList(answer.getSonSubjectId());
                updateListVo.add(updateVo);
                log.info("添加问答题试题答案[{}]:{}", x, JacksonUtil.toString(answer));
            }
            updateListSubject(updateListVo);
        }
    }

    public String updateListSubject(List<ExamSubjectUpdateListVo> voList) {
        String i = "";
        for (ExamSubjectUpdateListVo vo : voList) {

            List<ExamPaperSubject> examPaperSubjectList = examPaperSubjectMapper.selectList(Wrappers.lambdaQuery(ExamPaperSubject.class));
            List<ExamSubject> subjectList = examSubjectMapper.selectList(Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getTenantId, KefuContext.getKefuContext().getTenantId())
                    .ne(ExamSubject::getFatherSubject, "")
                    .isNotNull(ExamSubject::getFatherSubject));
            List<ExamSubjectAnswer> answerList = examSubjectAnswerMapper.selectList(Wrappers.lambdaQuery(ExamSubjectAnswer.class));
            if(vo.getSubjectList()!=null){
                vo.getSubjectList().forEach(examSubject -> {
                    examPaperSubjectList.forEach(paperSubject -> {
                        if (paperSubject.getSubjectId().equals(examSubject.getSubjectId())) {
                            throw new RuntimeException("您添加的子问题存在已关联问卷当中的问题,请检查！");
                        }
                    });
                    subjectList.forEach(subject -> {
                        if (examSubject.getSubjectId().equals(subject.getSubjectId())) {
                            throw new RuntimeException("您此次添加，子问题不可再次设置为子问题请检查！");
                        }
                        answerList.forEach(answer -> {
                            if (vo.getAnswerId().equals(answer.getAnswerId())){
                                if (answer.getSubjectId().equals(subject.getSubjectId())) {
                                    throw new RuntimeException("您此次添加父问题是子问题，请检查！");
                                }
                            }
                            if (examSubject.getSubjectId().equals(answer.getSubjectId())) {
                                if (subject.getFatherSubject().equals(answer.getAnswerId())) {
                                    throw new RuntimeException("您添加的子问题当中是父问题,请检查！");
                                }
                            }
                        });
                    });
                });
            }

            ExamSubject examSubject = new ExamSubject();
            LambdaQueryWrapper<ExamSubject> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ExamSubject::getTenantId, KefuContext.getKefuContext().getTenantId());
            examSubject.setFatherSubject(vo.getAnswerId());
            if (vo.getSubjectList() != null && vo.getSubjectList().size() > 0) {
                for (ExamSubject subject : vo.getSubjectList()) {
                    wrapper.eq(ExamSubject::getSubjectId, subject.getSubjectId())
                            .or();
                }
                i += String.valueOf(examSubjectMapper.update(examSubject, wrapper));
            }
        }
        return i;
    }

    public List<ExamSubjectAnswer> selectAnswer(ExamSubjectAnswerJumpVo vo) {
        List<ExamCascadeJump> examCascadeJumpList = examCascadeJumpMapper.selectList(Wrappers.lambdaQuery(ExamCascadeJump.class)
                .eq(ExamCascadeJump::getTenantId, KefuContext.getKefuContext().getTenantId())
                .eq(ExamCascadeJump::getSubjectId, vo.getSubjectId())
                .eq(ExamCascadeJump::getPaperId, vo.getPaperId()));
        List<ExamSubjectAnswer> examSubjectAnswers = examSubjectAnswerMapper.selectList(Wrappers.lambdaQuery(ExamSubjectAnswer.class)
                .eq(ExamSubjectAnswer::getSubjectId, vo.getSubjectId())
                .orderBy(true, true, ExamSubjectAnswer::getAnswerSort));
        List<ExamSubjectAnswer> examSubjectAnswerList = new ArrayList<>();
        for (ExamSubjectAnswer answer : examSubjectAnswers) {
            boolean flag = false;
            List<ExamSubject> examSubjectList = examSubjectMapper.selectList(Wrappers.lambdaQuery(ExamSubject.class)
                    .eq(ExamSubject::getFatherSubject, answer.getAnswerId())
                    .eq(ExamSubject::getTenantId, KefuContext.getKefuContext().getTenantId()));
            if (examSubjectList == null || examSubjectList.size() <= 0) {
                for (String answerId : vo.getAnswerList()) {
                    if (answer.getAnswerId().equals(answerId)) {
                        flag = true;
                    }
                }
                for (ExamCascadeJump jump : examCascadeJumpList)
                    if (jump.getAnswerId().equals(answer.getAnswerId())) {
                        flag = true;
                    }
                if (!flag) {
                    examSubjectAnswerList.add(answer);
                }
            }
        }
        return examSubjectAnswerList;
    }

    public List<ExamSubject> jumpSubject(ExamSubject examSubject) {
        ExamPaperSubject examPaperSubject = examPaperSubjectMapper.selectOne(Wrappers.lambdaQuery(ExamPaperSubject.class)
                .eq(ExamPaperSubject::getSubjectId, examSubject.getSubjectId())
                .eq(ExamPaperSubject::getPaperId, examSubject.getPaperId()));
        if (examPaperSubject == null) {
            JoinLambdaWrapper<ExamSubjectAnswer> wrapper = new JoinLambdaWrapper<>(ExamSubjectAnswer.class);
            wrapper.leftJoin(ExamSubject.class, ExamSubject::getFatherSubject, ExamSubjectAnswer::getAnswerId)
                    .eq(ExamSubject::getSubjectId, examSubject.getSubjectId())
                    .end();
            ExamSubjectAnswer answer = examSubjectAnswerMapper.joinSelectOne(wrapper, ExamSubjectAnswer.class);
            examPaperSubject = examPaperSubjectMapper.selectOne(Wrappers.lambdaQuery(ExamPaperSubject.class)
                    .eq(ExamPaperSubject::getSubjectId, answer.getSubjectId())
                    .eq(ExamPaperSubject::getPaperId, examSubject.getPaperId()));
        }
        JoinLambdaWrapper<ExamSubject> wrapper = new JoinLambdaWrapper<>(ExamSubject.class);
        wrapper.ne(ExamSubject::getSubjectId, examSubject.getSubjectId())
                .leftJoin(ExamPaperSubject.class, ExamPaperSubject::getSubjectId, ExamSubject::getSubjectId)
                .eq(ExamPaperSubject::getPaperId, examSubject.getPaperId())
                .gt(ExamPaperSubject::getSort, examPaperSubject.getSort())
                .end();
        List<ExamSubject> examSubjectList = examSubjectMapper.joinSelectList(wrapper, ExamSubject.class);
        LambdaQueryWrapper<ExamSubjectAnswer> answerWrapper = Wrappers.lambdaQuery(ExamSubjectAnswer.class);
        for (ExamSubject s : examSubjectList) {
            answerWrapper.eq(ExamSubjectAnswer::getSubjectId, s.getSubjectId())
                    .or();
        }
        List<ExamSubjectAnswer> examSubjectAnswers = examSubjectAnswerMapper.selectList(answerWrapper);
        LambdaQueryWrapper<ExamSubject> subjectWrapper = Wrappers.lambdaQuery(ExamSubject.class);
        for (ExamSubjectAnswer answer : examSubjectAnswers) {
            subjectWrapper.eq(ExamSubject::getFatherSubject, answer.getAnswerId())
                    .or();
        }
        List<ExamSubject> subjectList = examSubjectMapper.selectList(subjectWrapper);
        for (ExamSubject subject : subjectList) {
            examSubjectList.add(subject);
        }
        return examSubjectList;
    }
}
